#pragma once

#include <iostream>
#include <sys/select.h>
#include <sys/time.h>
#include "Socket.hpp"

using namespace std;

static const uint16_t default_port = 8080;
static const int fd_num_max = (sizeof(fd_set) * 8);
int default_fd = -1;

class Server
{
public:
    Server(uint16_t port = default_port)
    : _port(port)
    {
        for(int i=0; i<fd_num_max; i++)
        {
            fd_array[i] = default_fd;
        }
    }

    void Init()
    {
        _listen_sock.Socket();
        _listen_sock.Bind(_port);
        _listen_sock.Listen();
    }

    void Run()
    {
        //监听套接字加入fd数组
        fd_array[0] = _listen_sock.Fd();

        while(1)
        {
            //创建读事件位图集
            fd_set rfds;
            FD_ZERO(&rfds);

            //将有效fd对应的位图集位置置1，并获取fd中的最大值
            int max_fd = fd_array[0];
            for(int i=0; i<fd_num_max; i++)
            {
                if(fd_array[i] != default_fd)
                {
                    FD_SET(fd_array[i], &rfds);

                    if(max_fd < fd_array[i])
                    {
                        max_fd = fd_array[i];
                    }
                }
            }

            //设置等待时间
            struct timeval tv = {5, 0};

            //根据返回值做事，0等待超时，-1出错，其它表示有事件就绪
            int s = select(max_fd+1, &rfds, nullptr, nullptr, &tv);
            switch(s)
            {
            case 0:
                lg(Info, "timeout");
                break;
            case -1:
                lg(Error, "select err: %s[%d]", strerror(errno), errno);
                break;
            default:
                EventReady(rfds);
            }
        }
    }

    void PrintFdArray()
    {
        cout << "fd_list: ";
        for(int i=0; i<fd_num_max; i++)
        {
            if(fd_array[i] != default_fd)
            {
                cout << fd_array[i] << " ";
            }
        }
        cout << endl;
    }

    ~Server()
    {
        _listen_sock.Close();
    }

private:
    void EventReady(fd_set& rfds)
    {
        for(int i=0; i<fd_num_max; i++)
        {
            //遍历fd数组获取有效fd
            if(fd_array[i] != default_fd)
            {
                //根据内核给的就绪名单，看看哪些fd已就绪
                if(FD_ISSET(fd_array[i], &rfds))
                {
                    //监听fd处理监听事件，其它fd处理读事件
                    if(fd_array[i] == _listen_sock.Fd())
                    {
                        ListenEvent();
                    }
                    else
                    {
                        ReadEvent(fd_array[i], i);
                    }
                }
            }
        }
        
    }

    void ListenEvent()
    {
        //建立连接并获得新的fd
        string client_ip;
        uint16_t client_port;
        int accept_fd = _listen_sock.Accept(&client_ip, &client_port);

        //获取fd数组可用位置的下标
        int pos = 1;
        for(; pos<fd_num_max; pos++)
        {
            if(fd_array[pos] == default_fd)
            {
                fd_array[pos] = accept_fd;
                PrintFdArray();
                break;
            }
        }
        //fd数组无可用位置
        if(pos == fd_num_max)
        {
            lg(Warning, "fd_array full");
            close(accept_fd);
        }
    }

    void ReadEvent(int fd, int pos)
    {
        char buffer[1024];
        int r = read(fd, buffer, sizeof(buffer)-1);
        if(r > 0)
        {
            buffer[r] = 0;
            cout << "get msg: " << buffer << endl;
        }
        else if(r == 0)
        {
            lg(Info, "client quit");
            close(fd);
            fd_array[pos] = default_fd;
        }
        else
        {
            lg(Error, "read err: %s[%d]", strerror(errno), errno);
            close(fd);
            fd_array[pos] = default_fd;
        }
    }

private:
    Sock _listen_sock; //监听套接字
    uint16_t _port; //端口
    int fd_array[fd_num_max]; //辅助数组，负责维护fd
};